#include "rvASSEMBLECUBE.h"

rvASSEMBLECUBE::rvASSEMBLECUBE(IDirect3DDevice9* pDevice, IDirectInputDevice8* pDIDevKeyboard, IDirectInputDevice8* pDIDevMouse)
: m_pDevice(NULL),
  m_pDIDevKeyboard(NULL),
  m_pDIDevMouse(NULL),

  m_pCube(NULL),
  m_pInterface(NULL),
  m_pCamera(NULL),

  m_state(STATE_ENTRANCE)
{
	if( pDevice == NULL )
		::MessageBox(0, "rvASSEMBLECUBE - Device pointer value is NULL!", 0, 0);
	m_pDevice = pDevice;

	if( pDIDevKeyboard == NULL )
		::MessageBox(0, "rvASSEMBLECUBE - Input device pointer value is NULL!", 0, 0);
	m_pDIDevKeyboard = pDIDevKeyboard;

	if( pDIDevMouse == NULL )
		::MessageBox(0, "rvASSEMBLECUBE - Input device pointer value is NULL!", 0, 0);
	m_pDIDevMouse = pDIDevMouse;

	m_pCube = new rvACCube(m_pDevice);
	m_pInterface = new rvACInterface(m_pDevice);

	D3DXMATRIXA16 matTarget;
	D3DXMatrixIdentity(&matTarget);
	m_pCamera = new Camera(&matTarget, 7, 3.0f);

	m_pCamera->FTpitch(D3DX_PI / 4 * 3);
	m_pCamera->FTyaw(D3DX_PI / 4 * 5);

	m_pDevice->LightEnable(0, true);
}

rvASSEMBLECUBE::~rvASSEMBLECUBE()
{
	if( m_pCube )
		d3d::Delete<rvACCube*>(m_pCube);

	if( m_pInterface )
		d3d::Delete<rvACInterface*>(m_pInterface);

	if( m_pCamera )
		d3d::Delete<Camera*>(m_pCamera);
}

void rvASSEMBLECUBE::_goMenuState()
{
	m_pInterface->goMenu();

	m_state = STATE_MENU;
}

void rvASSEMBLECUBE::_goMuddlingState(const rvACInterface::GAMELEVEL gl)
{
	m_pInterface->muddlingNow(gl);

	int muddletime[3] = { 1, 20, 30 };
	m_pCube->startMuddle(muddletime[gl]);

	m_state = STATE_MUDDLE;
}

void rvASSEMBLECUBE::_goPlayingState()
{
	if( m_state == STATE_PAUSE )
	{
		m_pInterface->continueGame();
		m_pCube->continueGame();
	}
	else
		m_pInterface->startPlaying();

	m_state = STATE_PLAYING;
}

void rvASSEMBLECUBE::_goPauseState()
{
	m_pInterface->pauseGame();

	m_state = STATE_PAUSE;
}

void rvASSEMBLECUBE::_goCompleteState()
{
	m_pInterface->completeGame();

	m_state = STATE_COMPLETE;
}

void rvASSEMBLECUBE::_resetGame()
{
	m_pInterface->goEntrance();
	
	if( m_state != STATE_MENU )
		m_pCube->init();

	m_state = STATE_ENTRANCE;
}

void rvASSEMBLECUBE::_processofKeyboardInput(const float timeDelta)
{
	BYTE abyKSNow[256] = {0}; // KS;keyboard state
	d3d::ReadKeyboardState(m_pDIDevKeyboard, abyKSNow);

	switch(m_state)
	{
	case STATE_ENTRANCE:
		if( abyKSNow[ESC] & PRESS_ONLYONCE )
		{
			HWND hWnd = GetFocus();
			::DestroyWindow(hWnd);
		}
		else if( d3d::CheckPressAnyKeybyKeyboard(abyKSNow, PRESS_ONLYONCE) )
			_goMenuState();
		break;

	case STATE_MENU:
		if( abyKSNow[E] & PRESS_ONLYONCE ) // easy
			_goMuddlingState(rvACInterface::GL_EASY);
		else if( abyKSNow[N] & PRESS_ONLYONCE ) // normal
			_goMuddlingState(rvACInterface::GL_NORMAL);
		else if( abyKSNow[H] & PRESS_ONLYONCE ) // hard
			_goMuddlingState(rvACInterface::GL_HARD);
		else if( abyKSNow[ESC] & PRESS_ONLYONCE )
			_resetGame();
			
		break;

	case STATE_PLAYING:
		if( abyKSNow[A] & PRESS_ONLYONCE )
			m_pCube->shiftRow();
		if( abyKSNow[S] & PRESS_ONLYONCE )
			m_pCube->shiftAxis();
		
		if( abyKSNow[D] & PRESS_ONLYONCE )
			m_pCube->wheelRow(rvACCube::WHEEL_CCW, timeDelta);
		else if( abyKSNow[F] & PRESS_ONLYONCE )
			m_pCube->wheelRow(rvACCube::WHEEL_CW, timeDelta);

		if( abyKSNow[ESC] & PRESS_ONLYONCE && m_pCube->pauseGame() )
			_goPauseState();
		break;

	case STATE_PAUSE:
		if( abyKSNow[Y] & PRESS_ONLYONCE ) // yes
			_goPlayingState();
		else if( abyKSNow[N] & PRESS_ONLYONCE ) // no
			_resetGame();
		break;

	case STATE_COMPLETE:
		if( d3d::CheckPressAnyKeybyKeyboard(abyKSNow, PRESS_ONLYONCE) )
			_resetGame();
		break;
	}

	if( m_state != STATE_PAUSE )
	{
		if( abyKSNow[UP]    & PRESS_CONTINUOUS ) m_pCamera->FTpitch(timeDelta);
		if( abyKSNow[DOWN]  & PRESS_CONTINUOUS ) m_pCamera->FTpitch(-timeDelta);
		if( abyKSNow[LEFT]  & PRESS_CONTINUOUS ) m_pCamera->FTyaw(timeDelta);
		if( abyKSNow[RIGHT] & PRESS_CONTINUOUS ) m_pCamera->FTyaw(-timeDelta);
	}
}

void rvASSEMBLECUBE::_processofMouseInput(const float timeDelta)
{
	DIMOUSESTATE2 dims2Now;
	d3d::ReadMouseState(m_pDIDevMouse, &dims2Now);

	switch(m_state)
	{		
	case STATE_MENU:
		if( dims2Now.rgbButtons[0] & PRESS_ONLYONCE )
		{
			POINT pt;
			d3d::GetCursorPosInScreen(&pt);

			if( pt.x > d3d::WIDTH / 2 - 33 && pt.x < d3d::WIDTH / 2 + 33
				&& pt.y > d3d::HEIGHT / 4 * 3 - 25 && pt.y < d3d::HEIGHT / 4 * 3 - 5 ) // easy
				_goMuddlingState(rvACInterface::GL_EASY);
			else if( pt.x > d3d::WIDTH / 2 - 59 && pt.x < d3d::WIDTH / 2 + 59
				&& pt.y > d3d::HEIGHT / 4 * 3 && pt.y < d3d::HEIGHT / 4 * 3 + 20 ) // normal
				_goMuddlingState(rvACInterface::GL_NORMAL);
			else if( pt.x > d3d::WIDTH / 2 - 38 && pt.x < d3d::WIDTH / 2 + 38
				&& pt.y > d3d::HEIGHT / 4 * 3 + 25 && pt.y < d3d::HEIGHT / 4 * 3 + 45 ) // hard
				_goMuddlingState(rvACInterface::GL_HARD);
		}
		break;

	case STATE_PLAYING:
		if( m_pCube->isStop() )
		{
			if( dims2Now.rgbButtons[0] & PRESS_ONLYONCE )
			{
				POINT pt;
				d3d::GetCursorPosInScreen(&pt);

				D3DVIEWPORT9 vp;
				D3DXMATRIX   matProj, matViewInverse;
				m_pDevice->GetViewport(&vp);
				m_pDevice->GetTransform(D3DTS_PROJECTION, &matProj);
				m_pDevice->GetTransform(D3DTS_VIEW, &matViewInverse);
				D3DXMatrixInverse(&matViewInverse, 0, &matViewInverse);

				d3d::Ray pickingRay;
				d3d::CalcPickingRay(pt.x, pt.y, &vp, &matProj, &matViewInverse, &pickingRay);

				m_pCube->checkClick(&pickingRay);
			}
			
			if( dims2Now.lZ > 0 )
			{
				m_pCube->wheelRow(rvACCube::WHEEL_CCW, timeDelta);
			}
			if( dims2Now.lZ < 0 )
			{
				m_pCube->wheelRow(rvACCube::WHEEL_CW, timeDelta);
			}
		}
		break;
		
	case STATE_PAUSE:
		if( dims2Now.rgbButtons[0] & PRESS_ONLYONCE )
		{
			POINT pt;
			d3d::GetCursorPosInScreen(&pt);

			if( pt.x > d3d::WIDTH  / 4 - 56 && pt.x < d3d::WIDTH / 4 + 56
				&& pt.y > d3d::HEIGHT / 2 - 35 && pt.y < d3d::HEIGHT / 2 + 35 ) // yes
				_goPlayingState();
			else if( pt.x > d3d::WIDTH / 4 * 3 - 45 && pt.x < d3d::WIDTH / 4 * 3 + 45
				&& pt.y > d3d::HEIGHT / 2 - 35 && pt.y < d3d::HEIGHT / 2 + 35 ) // no
				_resetGame();
		}
		break;
	}

	if( m_state != STATE_PAUSE )
	{
		float fDelta = 0.005f;
		if( dims2Now.rgbButtons[0] & PRESS_CONTINUOUS )
			m_pCamera->FTyaw(fDelta * (float)dims2Now.lX);
		if( dims2Now.rgbButtons[0] & PRESS_CONTINUOUS )
			m_pCamera->FTpitch(fDelta * (float)dims2Now.lY);
	}
}

void rvASSEMBLECUBE::_setupBeforeDraw(const float timeDelta)
{
	_processofKeyboardInput(timeDelta);
	_processofMouseInput(timeDelta);

	switch(m_state)
	{
	case STATE_MUDDLE:
		if( m_pCube->isStop() )
			_goPlayingState();
		break;
	}

	if( m_pCube->setupBeforeDraw(timeDelta) )
		_goCompleteState();
	
	D3DXVECTOR3 vDir;
	m_pCamera->getLook(&vDir);
	D3DXCOLOR c = d3d::WHITE;
	if( m_state == STATE_PAUSE )
		c *= 0.1f;
	D3DLIGHT9 dirLight = d3d::InitDirectionalLight(&vDir, &c);
	m_pDevice->SetLight(0, &dirLight);

	D3DXMATRIX V;
	m_pCamera->getViewMatrix(&V);
	m_pDevice->SetTransform(D3DTS_VIEW , &V);
}

void rvASSEMBLECUBE::draw(const float timeDelta)
{
	_setupBeforeDraw(timeDelta);

	m_pCube->draw();
	m_pInterface->draw();
}